package com.bianguo.android.ioclibrary;

import android.app.Application;
import android.content.Context;
import android.net.ConnectivityManager;
import android.net.NetworkRequest;
import android.os.Build;
import android.text.TextUtils;

import com.bianguo.android.ioclibrary.annotations.Network;
import com.bianguo.android.ioclibrary.bean.NetworkBean;
import com.bianguo.android.ioclibrary.enums.NetworkState;

import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;

public class NetworkManager {

    private static volatile NetworkManager instance;
    private HashMap<Object, ArrayList<NetworkBean>> stateMap;
    private Application application;

    private NetworkManager() {
        stateMap = new HashMap<>();
    }

    public static NetworkManager getDefault() {
        NetworkManager manager = instance;
        if (manager == null) {
            synchronized (NetworkManager.class) {
                if (manager == null) {
                    manager = new NetworkManager();
                    instance = manager;
                }
            }
        }
        return manager;
    }

    /**
     * 初始化网络监听，在Application中初始化
     * 如果不初始化就监听不到
     * @param application
     */
    public void init(Application application) {
        if (application == null) {
            return;
        }
        this.application = application;
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
            ConnectivityManager.NetworkCallback networkCallback = new NetworkCallback();
            ConnectivityManager manager = (ConnectivityManager) application.getSystemService(Context.CONNECTIVITY_SERVICE);
            if (manager != null) {
                manager.requestNetwork(new NetworkRequest.Builder().build(), networkCallback);
            }
        }
    }

    /**
     * 注册监听
     * @param target
     */
    public void register(Object target) {
        if (isRegister(target)) {
            return;
        }
        stateMap.put(target, subscribe(target));
    }

    private ArrayList<NetworkBean> subscribe(Object target) {
        ArrayList<NetworkBean> networkBeans = new ArrayList<>();
        Class<?> clazz = target.getClass();
        if (clazz != null) {
            Method[] methods = clazz.getDeclaredMethods();
            for (Method method : methods) {
                Network network = method.getAnnotation(Network.class);
                if (network != null) {
                    //方法返回类型
                    Class<?> returnType = method.getReturnType();
                    //方法的参数
                    Class<?>[] parameterTypes = method.getParameterTypes();
                    if (TextUtils.equals("void", returnType.toString()) && parameterTypes.length == 1) {
                        NetworkBean networkBean = new NetworkBean();
                        networkBean.setMethod(method);
                        networkBean.setState(network.state());
                        networkBean.setParamType(parameterTypes[0]);
                    }
                }
            }
        }
        return networkBeans;
    }

    public void post(NetworkState networkState) {
        Iterator<Object> iterator = stateMap.keySet().iterator();
        while (iterator.hasNext()) {
            Object key = iterator.next();
            ArrayList<NetworkBean> networkBeans = stateMap.get(key);
            if (networkBeans != null) {
                for (NetworkBean networkBean : networkBeans) {
                    if (networkBean.getParamType().isAssignableFrom(networkState.getClass())) {
                        switch (networkBean.getState()) {
                            case AUTO:
                                invoke(networkBean, key, networkState);
                                break;
                            case WIFI:
                                if (networkState == NetworkState.WIFI || networkState == NetworkState.NONE) {
                                    invoke(networkBean, key, networkState);
                                }
                                break;
                            case CELLULAR:
                                if (networkState == NetworkState.CELLULAR || networkState == NetworkState.NONE) {
                                    invoke(networkBean, key, networkState);
                                }
                                break;
                            case NONE:
                                if (networkState == NetworkState.NONE) {
                                    invoke(networkBean, key, networkState);
                                }
                                break;
                        }
                    }
                }
            }
        }
    }

    private void invoke(NetworkBean networkBean, Object target, NetworkState networkState) {
        Method method = networkBean.getMethod();
        try {
            method.invoke(target, networkState);
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        } catch (InvocationTargetException e) {
            e.printStackTrace();
        }
    }

    public void unRegister(Object target) {
        if (!stateMap.isEmpty()) {
            stateMap.remove(target);
        }
    }

    public void unRegisterAll() {
        if (!stateMap.isEmpty()) {
            stateMap.clear();
        }
    }

    public boolean isRegister(Object target) {
        return stateMap.containsKey(target);
    }
}
